#include "gtest/gtest.h"
#include "PANEApp.h"
namespace PANEApp {

class MyVideoTraceAppTest: public testing::Test {
protected:

	static PANEButtonElement * createButton( Document * doc, string prefix, string suffix ) {
		PANEButtonElement * btn = dynamic_cast< PANEDocument * >( doc )->createPANEButtonElement();
		btn->setNormalImage( prefix + "0" + suffix );
		btn->setMouseDownImage( prefix + "1" + suffix );
		btn->setMouseOverImage( prefix + "2" + suffix );
		return btn;
	}

	Element * buildNavigationBar( Document * doc ) {
		btnLeftMost = createButton( doc, "data/btn/leftMost", ".png" );
		btnLeft = createButton( doc, "data/btn/left", ".png" );
		btnPlay = createButton( doc, "data/btn/play", ".png" );
		btnRight = createButton( doc, "data/btn/right", ".png" );
		btnRightMost = createButton( doc, "data/btn/rightMost", ".png" );
		btnSave = createButton( doc, "data/btn/save", ".png" );

		Element * nav = doc->createElement("DIV");
		nav->appendChild( btnLeftMost );
		nav->appendChild( btnLeft );
		nav->appendChild( btnPlay );
		nav->appendChild( btnRight );
		nav->appendChild( btnRightMost );
		nav->appendChild( btnSave );
		return nav;
	}

	PANERadioElement * buildToolBar( Document * doc ) {
		btnDrawDot = createButton( doc, "data/btn/dot", ".bmp" );
		btnDrawLine = createButton( doc, "data/btn/line", ".bmp" );
		btnErase = createButton( doc, "data/btn/erase", ".bmp" );
		btnMove = createButton( doc, "data/btn/move", ".bmp" );

		tool = dynamic_cast< PANERadioElement * >( doc->createElement("RADIO") );
		tool->appendChild( btnDrawDot );
		tool->appendChild( btnDrawLine );
		tool->appendChild( btnErase );
		tool->appendChild( btnMove );
		return tool;
	}

	PANEImageBoardElement * buildImageBoard( Document * doc ) {
		board = dynamic_cast< PANEImageBoardElement * >( doc->createElement("BOARD") );

		vd = new VoodooLoader();
		model = new ModelReconstructor();

		model->importVoodoo( vd );
		board->setModelReconstructor( model );

		return board;
	}

	Element * buildRoot( Document * doc ) {
		Element * root = doc->createElement("DIV");
		root->setAttribute("WIDTH", "700");
		root->setAttribute("HEIGHT", "550");

		Element * nav = buildNavigationBar( doc );
		root->appendChild( nav );

		Element * tool = buildToolBar( doc );
		root->appendChild( tool );

		Element * imageBoard = buildImageBoard( doc );
		root->appendChild( imageBoard );

		return root;
	}

	class NaviEventListener : IMPLEMENTS( EventListener ) {
	public:
		typedef enum { BtnLeftMost, BtnLeft, BtnPlay, BtnRight, BtnRightMost } ButtonType;
		NaviEventListener( PANEImageBoardElement * board, ButtonType btnType )
		: board_(board), btnType_(btnType), step_(1)
		{}

		virtual void handleEvent(Event * evt) {
			const FrameNumber currentFrameNumber = board_->getCurrentFrameNumber();
			const FrameNumber maxFrameNumber = board_->getNumberOfFrames() - 1;
			const MouseEvent * const mouseEvt = dynamic_cast< MouseEvent * >( evt );
			unsigned long step = ( mouseEvt->getCtrlKey() ? 20 : step_ );

			if( btnType_ == BtnLeftMost )
				board_->setCurrentFrameNumber( 0 );
			else if( btnType_ == BtnLeft && currentFrameNumber > 0 ) {
				step = std::min( step, currentFrameNumber );
				board_->setCurrentFrameNumber( currentFrameNumber - step );
			} else if( btnType_ == BtnRight && currentFrameNumber < maxFrameNumber )
				board_->setCurrentFrameNumber( std::min( maxFrameNumber, currentFrameNumber + step ) );
			else if( btnType_ == BtnRightMost )
				board_->setCurrentFrameNumber( maxFrameNumber );
			else if( btnType_ == BtnPlay ) {

			}
		}
	private:
		PANEImageBoardElement * board_;
		ButtonType btnType_;
		unsigned long step_;
	};

	class ToolEventListener : IMPLEMENTS( EventListener ) {
	public:
		ToolEventListener( PANEImageBoardElement * board, PANEImageBoardElement::InteractionMethod btnType )
		: board_(board), btnType_(btnType)
		{}
		virtual void handleEvent(Event * evt) {
			board_->setInteractionMethod( btnType_ );
		}
	private:
		PANEImageBoardElement * board_;
		PANEImageBoardElement::InteractionMethod btnType_;
	};

	class SaveEventListener : IMPLEMENTS( EventListener ) {
	public:
		SaveEventListener(ModelReconstructor * mode, string filenameForSaving)
		: model_(mode)
		, filenameForSaving_(filenameForSaving)
		{}
		virtual void handleEvent(Event * evt) {
			model_->saveReconstructedModelOnFile( filenameForSaving_ );
		}
	private:
		ModelReconstructor * model_;
		string filenameForSaving_;
	};

	void buildMouseEvents() {
		btnLeftMost->addEventListener( MouseEventImp::EVENT_CLICK, new NaviEventListener( board, NaviEventListener::BtnLeftMost ), false );
		btnLeft->addEventListener( MouseEventImp::EVENT_CLICK, new NaviEventListener( board, NaviEventListener::BtnLeft ), false );
		btnRight->addEventListener( MouseEventImp::EVENT_CLICK, new NaviEventListener( board, NaviEventListener::BtnRight ), false );
		btnRightMost->addEventListener( MouseEventImp::EVENT_CLICK, new NaviEventListener( board, NaviEventListener::BtnRightMost ), false );

		btnDrawDot->addEventListener( MouseEventImp::EVENT_CLICK, new ToolEventListener( board, PANEImageBoardElement::DrawPoint ), false );
		btnDrawLine->addEventListener( MouseEventImp::EVENT_CLICK, new ToolEventListener( board, PANEImageBoardElement::DrawLine ), false );
		btnErase->addEventListener( MouseEventImp::EVENT_CLICK, new ToolEventListener( board, PANEImageBoardElement::Erase ), false );
		btnMove->addEventListener( MouseEventImp::EVENT_CLICK, new ToolEventListener( board, PANEImageBoardElement::Move ), false );

		btnSave->addEventListener( MouseEventImp::EVENT_CLICK, new SaveEventListener( model, filenameForSaving ), false );
	}

	virtual void SetUp() {
		filenameForSaving = "reconstructed.x3d";

		app = new MyVideoTraceApp();

		app->createWindow("MyVideoTrace");
		ASSERT_TRUE(app->isWindowCreated()) << "Window is not created.";

		doc = new PANEDocument();
		app->setDocument( doc );

		root = buildRoot( doc );
		doc->appendChild(root);

		buildMouseEvents();
	}

	virtual void TearDown() {
		app->destroyWindow();
		ASSERT_FALSE(app->isWindowCreated()) << "Window cannot be destroyed.";

		delete model;
    	delete vd;
		delete app;
	}

	MyVideoTraceApp * app;
	Document * doc;
	Element * root;

	PANEButtonElement *btnLeftMost, *btnLeft, *btnPlay, *btnRight, *btnRightMost, *btnSave;

	PANERadioElement * tool;
	PANEButtonElement *btnDrawDot, *btnDrawLine, *btnErase, *btnMove;

	PANEImageBoardElement * board;
    VoodooLoader * vd;
	ModelReconstructor * model;

	string filenameForSaving;
};

TEST_F(MyVideoTraceAppTest, TestDriver) {
	FAIL();
//	Element * img = doc->createElement( PANEImageElement::TagName );
//	root->appendChild( img );
//
//	img->setAttribute( "SRC", "../VoodooData/car000.jpeg" );

	int step = 5;
	int numberOfFrames = 420;
//	int numberOfFrames = 10;
	vd->loadCameraData("../VoodooData/car.txt");
	vd->loadFeaturePoints( "../VoodooData/car", 0, numberOfFrames, ".pnt", step );
	board->loadImageFiles( "../VoodooData/car", 0, numberOfFrames, ".jpeg", step );

	board->setCurrentFrameNumber(0);
	board->setInteractionMethod( PANEImageBoardElement::DrawPoint );

	app->updateView();
	for( int i = 0; i < 10; ++ i) app->fetchEvents();
	while(true) app->fetchEvents();
}

TEST_F(MyVideoTraceAppTest, TestDriverForBody) {
//	FAIL();
//	Element * img = doc->createElement( PANEImageElement::TagName );
//	root->appendChild( img );
//
//	img->setAttribute( "SRC", "../VoodooData/car000.jpeg" );

	int step = 5;
	int numberOfFrames = 995;
//	int numberOfFrames = 10;
	vd->loadCameraData("../VoodooData2/body.txt");
	vd->loadFeaturePoints( "../VoodooData2/body", 0, numberOfFrames, ".pnt", step );
	board->loadImageFiles( "../VoodooData2/body", 0, numberOfFrames, ".jpeg", step );

	board->setCurrentFrameNumber(0);
	board->setInteractionMethod( PANEImageBoardElement::DrawPoint );

	app->updateView();
	for( int i = 0; i < 10; ++ i) app->fetchEvents();
	while(true) app->fetchEvents();
}

//TEST_F(MyVideoTraceAppTest, ShowAButton) {
//	PANEButtonElement * btn = dynamic_cast< PANEButtonElement * >( doc->createElement("BUTTON") );
//	root->appendChild( btn );
//
//	btn->setNormalImage( "data/btn/play0.png" );
//	btn->setMouseDownImage( "data/btn/play1.png" );
//	btn->setMouseOverImage( "data/btn/play2.png" );
//
//	app->updateView();
//}

//TEST_F(MyVideoTraceAppTest, FetchMouseEvent) {
//}
//
//TEST_F(MyVideoTraceAppTest, ClickAButton) {
//}
//
//TEST_F(MyVideoTraceAppTest, Layout) {
//}
//
//TEST_F(MyVideoTraceAppTest, ShowToolList) {
//}
//
//TEST_F(MyVideoTraceAppTest, ShowNavigator) {
//}
//
//TEST_F(MyVideoTraceAppTest, ShowMenu) {
//}
//
//TEST_F(MyVideoTraceAppTest, ShowImages) {
//}
//
//TEST_F(MyVideoTraceAppTest, NavigateImages) {
//}
//
//TEST_F(MyVideoTraceAppTest, LoadDataFile){
//}
//
}
